package com.heima.comment.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.api.IApUserFeignClient;
import com.heima.comment.dtos.CommentLikeDto;
import com.heima.comment.dtos.CommentListDto;
import com.heima.comment.dtos.CommentSaveDto;
import com.heima.comment.pojos.ApComment;
import com.heima.comment.pojos.ApCommentLike;
import com.heima.comment.pojos.ApCommentVo;
import com.heima.comment.service.CommentService;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.threadLocal.ApUserThreadLocalUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CommentServiceImpl implements CommentService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private IApUserFeignClient iApUserFeignClient;

    @Autowired
    private GreenTextScan greenTextScan;

    /**
     * 保存评论列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult saveComment(CommentSaveDto dto) {
        //1.参数效验
        if (dto.getArticleId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "当前文章id不存在");
        }
        if (dto.getContent() == null || dto.getContent().equals("") || dto.getContent().length() > 140) {
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "发表的内容出现了问题");
        }

        //评论内容审核

        //1.5.判断当前是否用户登录还是游客登录
        ApUser apUser = ApUserThreadLocalUtil.getApUser();
        if (apUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        Integer userId = apUser.getId();
        if (userId == 0) {
            //2.1如果是游客则不可以执行以下操作
            return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH, "游客身份,没有权限发表评论");
        }
        //2.查询redis,如果redis中有值,直接使用用户信息,如果没有值,则远程调用fegin,同时也要缓存到redis
        String key = "LOGIN_USER_" + userId;
        String userStr = redisTemplate.opsForValue().get(key);
        if (userStr == null) {//表示不存在
            //远程调用feign
            apUser = iApUserFeignClient.findById(userId);
            //保存数据到redis中
            redisTemplate.opsForValue().set(key, JSON.toJSONString(apUser), 2, TimeUnit.HOURS);
        } else {//表存在
            apUser = JSON.parseObject(userStr, ApUser.class);
        }
        //3.保存数据到mongo
        ApComment apComment = new ApComment();
        apComment.setLikes(0);//点赞数
        apComment.setUserId(apUser.getId());
        apComment.setCreatedTime(new Date());
        apComment.setContent(dto.getContent());
        apComment.setNickName(apUser.getName());
        apComment.setReply(0);
        apComment.setUpdatedTime(new Date());
        apComment.setTargetId(String.valueOf(dto.getArticleId()));
        mongoTemplate.save(apComment);
        //4.返回结果
        return ResponseResult.okResult("发表评论完成");
    }

    /**
     * 评论点赞
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult likeComment(CommentLikeDto dto) {
        //1.参数效验
        if (dto.getCommentId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "评论id为空");
        }
        //2.判断当前是否是登录用户还是游客身份
        ApUser apUser = ApUserThreadLocalUtil.getApUser();
        if (apUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        Integer userId = apUser.getId();
        if (userId == 0) {
            //2.1如果是游客则不可以执行以下操作
            return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH, "游客身份,没有权限发表评论");
        }
        //3.查询当前评论信息是否存在
        ApComment apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);
        if (apComment == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "没有查询到评论信息");
        }
        String key = "COMMENT_LIKE_" + userId;
        //4.当前如果已经点赞过,且正在执行的是点赞动作则终止
        Boolean flag = redisTemplate.opsForSet().isMember(key, dto.getCommentId());
        if (dto.getOperation() == 0 && flag) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_EXIST, "当前用户已经点赞过该评论");
        }
        //5.当前如果已经点赞过,且正在执行的是取消点赞动作,则删除redis和mongo
        if (flag && dto.getOperation() == 1) {
            redisTemplate.opsForSet().remove(key, dto.getCommentId());

            mongoTemplate.remove(Query.query(Criteria.where("userId").is(userId).and("targetId").is(dto.getCommentId())), ApCommentLike.class);
            //修改评论集合数量-1
            Query query = Query.query(Criteria.where("id").is(userId).and("id").is(dto.getCommentId()));
            /**
             * inc表示自增的api.保证数据不会小于0
             * 参数一表示具体执行的哪个字段,
             * 参数二表示自增的数量,如果自增的话为正数,如果自减,为负数
             */
            UpdateDefinition update = new Update().inc("likes", -1);
            mongoTemplate.updateFirst(query, update, ApComment.class);
        }
        //6.当前如果没有点赞过,且正在执行的是点赞动作,则新增redis和mongo
        if (!flag && dto.getOperation() == 0) {
            redisTemplate.opsForSet().add(key, dto.getCommentId());
            ApCommentLike apCommentLike = new ApCommentLike();
            apCommentLike.setUserId(userId);
            apCommentLike.setCreatedTime(new Date());
            apComment.setTargetId(dto.getCommentId());
            mongoTemplate.insert(apComment);
            //7.当前如果没有点赞过,且正在执行的是取消点赞动作,则终止
        }
        //8.返回数据
        apComment = mongoTemplate.findById(dto.getCommentId(),ApComment.class);
        Map map = new HashMap();
        map.put("like",apComment.getLikes());
        return ResponseResult.okResult(map);
    }

    /**
     * 加载评论列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult listComment(CommentListDto dto) {
        //1.检查参数
        if (dto.getArticleId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        if (dto.getSize() == null || dto.getSize() == 0) {
            dto.setSize(10);
        }
        dto.setSize(Math.min(dto.getSize(), 50));

        //2.根据文章id查询评论集合类别
        Query query = Query.query(Criteria.where("targetId").is(dto.getArticleId().toString()))
                .with(Sort.by(Sort.Direction.DESC, "updatedTime"))
                .limit(dto.getSize());
        List<ApComment> apCommentList = mongoTemplate.find(query,ApComment.class);
        //3.如果是游客身份,直接返回列表
        ApUser apUser = ApUserThreadLocalUtil.getApUser();
        if (apUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        Integer userId = apUser.getId();
        if (userId == 0) {
            //3.1如果是游客只允许看到评论即可
            return ResponseResult.okResult(apCommentList);
        }
        //4.如果是登录用户的话,要进行高亮
           //4.1先根据用户id去查询当前用户是否点赞过某个评论,没有点赞过,直接返回list数据
        String key="COMMENT_LIKE" + userId;
            //根据key获取所有的value
        Set<String> members = redisTemplate.opsForSet().members(key);
        if (members==null){//说明当前用户并没有点赞过任何评论
            return ResponseResult.okResult(apCommentList);
        }
            //否则就是点赞过,进行高亮设置
        if (apCommentList!=null && apCommentList.size()>0){
            List<ApCommentVo> apCommentVoList = apCommentList.stream().map(apComment -> {
                //目的是要从apComment对象转换成apCommentVo对象
                ApCommentVo vo = new ApCommentVo();
                BeanUtils.copyProperties(apComment, vo);
                //如果redis的集合中包含了该评论id
                if (members.contains(apComment.getId())) {
                    //点赞
                    vo.setOperation((short) 0);
                }
                return vo;
            }).collect(Collectors.toList());
            return ResponseResult.okResult(apCommentVoList);
        }
        //5.返回数据
        return null;
    }
}

